package com.gnerv.sylvanas.module.mybatis.interceptor;

import com.zaxxer.hikari.pool.ProxyPreparedStatement;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.binding.MapperMethod;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.session.ResultHandler;

import java.sql.Statement;
import java.util.List;
import java.util.Map;

@Slf4j
@Intercepts({
        @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}),
        @Signature(type = StatementHandler.class, method = "query", args = {Statement.class, ResultHandler.class})
})
public class CommonParameterInterceptor implements Interceptor {

    public final List<CommonParameterHandler> commonParameterHandlerList;

    public CommonParameterInterceptor(List<CommonParameterHandler> commonParameterHandlerList) {
        this.commonParameterHandlerList = commonParameterHandlerList;
    }

    @Override
    public Object intercept(Invocation invocation) throws Throwable {

        if (invocation.getArgs()[0] instanceof ProxyPreparedStatement proxyPreparedStatement) {
            log.debug("proxyPreparedStatement: {}", proxyPreparedStatement);
        }
        if (invocation.getArgs()[0] instanceof MappedStatement) {
            if (invocation.getArgs().length > 1 && invocation.getArgs()[1] instanceof MapperMethod.ParamMap paramMap) {
                for (CommonParameterHandler commonParameterHandler : commonParameterHandlerList) {
                    Map<String, Object> parameters = commonParameterHandler.getParameters();
                    paramMap.putAll(parameters);
                }
                invocation.getArgs()[1] = paramMap;
            }
        }
        return invocation.proceed();
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

}